package com.sec.android.app.myfiles.module.abstraction;

import android.annotation.SuppressLint;
import android.content.Context;
import android.database.Cursor;
import android.database.StaleDataException;
import android.net.Uri;
import android.support.v4.view.animation.PathInterpolatorCompat;
import android.text.TextUtils;
import android.text.format.Formatter;
import android.util.LruCache;
import android.util.SparseArray;
import android.view.InflateException;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.ViewStub;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.ResourceCursorAdapter;
import android.widget.TextView;

import com.sec.android.app.myfiles.R;
import com.sec.android.app.myfiles.decorator.AbsAdapterImpDecorator;
import com.sec.android.app.myfiles.feature.layout.split.AbsLeftPanelFragment;
import com.sec.android.app.myfiles.feature.layout.split.TabletLeftPanelFragment;
import com.sec.android.app.myfiles.fragment.AbsMyFilesFragment;
import com.sec.android.app.myfiles.info.AppConstants;
import com.sec.android.app.myfiles.info.AppConstants.SortByType;
import com.sec.android.app.myfiles.info.AppFeatures;
import com.sec.android.app.myfiles.info.FileType;
import com.sec.android.app.myfiles.info.MediaFile;
import com.sec.android.app.myfiles.log.Log;
import com.sec.android.app.myfiles.module.ModuleLoader;
import com.sec.android.app.myfiles.module.abstraction.FileRecord.StorageType;
import com.sec.android.app.myfiles.module.local.category.CategoryDbTableInfo;
import com.sec.android.app.myfiles.navigation.NavigationInfo;
import com.sec.android.app.myfiles.navigation.NavigationInfo.NavigationMode;
import com.sec.android.app.myfiles.provider.DbTableInfo;
import com.sec.android.app.myfiles.provider.DbTableInfo.COLUMN_ID;
import com.sec.android.app.myfiles.thumbnail.ThumbnailImageView;
import com.sec.android.app.myfiles.thumbnail.ThumbnailMgr;
import com.sec.android.app.myfiles.util.FileExecute;
import com.sec.android.app.myfiles.util.FileUtils;
import com.sec.android.app.myfiles.util.PreferenceUtils;
import com.sec.android.app.myfiles.util.UiUtils;
import com.sec.android.app.myfiles.util.region.RegionUtils;
import com.sec.android.app.myfiles.widget.listview.AbsListViewImp;
import com.sec.android.app.myfiles.widget.listview.FileListViewHolder;
import com.sec.android.app.myfiles.widget.listview.ListViewHolder;
import com.sec.android.app.myfiles.widget.listview.ReverseCheckBox;

import java.util.Arrays;
import java.util.Locale;

/**
 * Abstract class for Adapter Implement
 *
 * @author jae.bae
 */
public abstract class AbsFileListAdapterImp extends ResourceCursorAdapter {
    private static final int ITEM_VIEW_TYPE_GROUP_HEADER = 0;
    private static final int ITEM_VIEW_TYPE_ITEM = 1;

    protected Context mContext;
    protected FileRecord mCurRecord;
    protected NavigationInfo mNavigationInfo;
    protected DbTableInfo mTableInfo;

    protected AbsListViewImp mListView;

    protected boolean mCheckMode;
    protected boolean mShareMode;

    private boolean mSelectAll;

    private LruCache<Integer, FileRecord> mRecords;

    private int mDragPosition = -1;

    private AbsAdapterImpDecorator mDecorator;
    private int[] mGroupSizes;


    /**
     * cache value for performance
     */
    @SuppressLint("UseSparseArrays")
    // need to null check
    protected SparseArray<Boolean> mIsCheckable = new SparseArray<>();

    public AbsFileListAdapterImp(Context context, NavigationInfo navigationInfo, AbsListViewImp listView, Cursor c, int flags) {
        super(context, listView.getItemLayoutId(), c, flags);

        _AbsFileListAdapterImp(context, navigationInfo, listView, c, flags);
    }

    protected AbsFileListAdapterImp(Context context, NavigationInfo navigationInfo, int layout, Cursor c, int flags) {
        super(context, layout, c, flags);
        _AbsFileListAdapterImp(context, navigationInfo, null, c, flags);
    }

    private void _AbsFileListAdapterImp(Context context, NavigationInfo navigationInfo, AbsListViewImp listView, Cursor c, int flags) {
        mContext = context;
        mListView = listView;

        mNavigationInfo = navigationInfo;
        if (navigationInfo != null) {
            mCurRecord = navigationInfo.getCurRecord();
        }
        mTableInfo = ModuleLoader.getInstance().getTableInfo(getStorageType());

        mCheckMode = false;
        mShareMode = false;
    }

    public FileRecord getCurRecord() {
        return mCurRecord;
    }

    private NavigationInfo getCurNavigationInfo() {
        return mNavigationInfo;
    }

    public void setDecorator(AbsAdapterImpDecorator decorator) {
        if (mDecorator == null) {
            mDecorator = decorator;
        } else {
            mDecorator.add(decorator);
        }
    }

    @Override
    public boolean areAllItemsEnabled() {
        return mGroupSizes == null;
    }

    @Override
    public final boolean isEnabled(int position) {
        boolean ret;
        if (mGroupSizes != null) {
            if (isGroupHeader(position)) {
                ret = false;
            } else {
                ret = _isEnabled(position);
            }
        } else {
            ret = _isEnabled(position);
        }
        return ret;
    }

    public boolean _isEnabled(int position) {
        return super.isEnabled(position);
    }

    @Override
    public int getViewTypeCount() {
        return 2;
    }

    @Override
    public int getItemViewType(int position) {
        if (isGroupHeader(position)) {
            return ITEM_VIEW_TYPE_GROUP_HEADER;
        }
        return ITEM_VIEW_TYPE_ITEM;
    }

    @Override
    public int getCount() {
        int ret = super.getCount();
        if (mGroupSizes != null) {
            ret += mGroupSizes.length;
        }
        return ret;
    }

    public DbTableInfo getTableInfo() {
        return mTableInfo;
    }

    /**
     * <pre>
     * bind view method
     *
     * note: Do not override or fix this method but override
     *       {@link #_bindView(Context, ListViewHolder, View, FileRecord, int)}
     *       {@link #_bindCheckView(ListViewHolder, View, FileRecord, int)}
     *       {@link #_bindDefaultInfoView(Context, ListViewHolder, FileRecord)}
     * {@link #_bindThumbnailView(Context, ListViewHolder, View, FileRecord)}
     */
    @Override
    public final void bindView(View v, Context context, Cursor c) {
        ListViewHolder vh = (ListViewHolder) v.getTag();
        if (vh != null) {
            int listPosition = getListPosition(c.getPosition());
            FileRecord record = getFileRecord(listPosition);
            if (!UiUtils.isSectionDivider(record)) {
                _bindView(context, vh, v, record, listPosition);
            } else {
                _bindNullView(context, vh, v, record, listPosition);
            }
        }
    }

    protected boolean isGroupHeader(int positionInList) {
        boolean ret = false;
        if (mGroupSizes != null && mGroupSizes.length > 0) {
            int index = 0;
            do {
                if (positionInList == 0) {
                    ret = true;
                }
                positionInList = positionInList - mGroupSizes[index++] - 1; // 1 is group header.
            } while (positionInList >= 0 && index < mGroupSizes.length);
        }
        return ret;
    }

    protected int getGroupPosition(int positionInList) {
        int ret = -1;
        if (mGroupSizes != null) {
            int index = 0;
            while (index < mGroupSizes.length) {
                positionInList = positionInList - (1 + mGroupSizes[index]);
                if (positionInList < 0) {
                    ret = index;
                    break;
                }
                index++;
            }
        }
        return ret;
    }

    /**
     * calculate cursor position of list position.
     *
     * @param positionInList
     * @return
     */
    private int getItemPosition(int positionInList) {
        if (mGroupSizes != null) {
            positionInList = positionInList - (getGroupPosition(positionInList) + 1);
            if (positionInList < 0) {
                positionInList = 0;
            }
        }
        return positionInList;
    }

    /**
     * calculate list position of cursor position
     *
     * @param itemPosition
     * @return
     */
    private int getListPosition(int itemPosition) {
        if (mGroupSizes != null) {
            int sum = 0;
            for (int i = 0; i < mGroupSizes.length; i++) {
                sum += mGroupSizes[i];
                if (sum > itemPosition) {
                    itemPosition += (i + 1);
                    break;
                }
            }
        }
        return itemPosition;
    }

    protected View _newGroupHeaderView(Context context, ListViewHolder vh, int groupPosition) {
        return null;
    }

    protected void _bindGroupHeaderView(Context context, ListViewHolder vh, View v, int groupPosition) {
    }

    protected void _bindNullView(Context context, ListViewHolder vh, View v, FileRecord record, int position) {
    }

    protected void _bindView(Context context, ListViewHolder vh, View v, FileRecord record, int position) {
        _bindThumbnailView(context, vh, v, record);
        _bindDefaultInfoView(context, vh, record);
        if (AppFeatures.SUPPORT_FOLDER_DESCRIPTION) {
            if (!isGridList()) {
                _bindFolderDescriptionView(vh, record);
            }
        }

        _bindCheckView(vh, v, record, position);
        _bindPickerPlayIcon(context, vh, v, record);
        _bindContentDescription(context, vh, v, record, position);

        if (mDecorator != null) {
            mDecorator.bindView(context, vh, v, record, position);
        }
    }

    /**
     * Bind FileRecord to view holder
     *
     * @param context
     * @param vh
     * @param record
     */
    protected void _bindDefaultInfoView(Context context, ListViewHolder vh, FileRecord record) {
        TextView textName = vh.getView(FileListViewHolder.NAME, TextView.class);
        if (textName != null) {
            String name;
            if (UiUtils.isInRTLMode(context)) {
                name = record.getName();
                if (!((name.charAt(0) >= 32 && name.charAt(0) <= 47) || (name.charAt(0) >= 58 && name.charAt(0) <= 64) || (name.charAt(0) >= 91 && name.charAt(0) <= 96))) {
                    name = "\u200F" + name;
                }
            } else {
                name = "\u200E" + record.getName();
            }
            textName.setText(name);
            textName.setEllipsize(TextUtils.TruncateAt.MIDDLE);
        }

        TextView textDate = vh.getView(FileListViewHolder.DATE, TextView.class);
        if (textDate != null) {
            textDate.setVisibility(View.VISIBLE);
            textDate.setText(UiUtils.makeTimeString(mContext, record.getDate()));
        }

        TextView textSize = vh.getView(FileListViewHolder.SIZE, TextView.class);
        if (textSize != null) {
            textSize.setVisibility(View.VISIBLE);

            if (record.getFileType() != FileType.FOLDER) {
                textSize.setText(UiUtils.makeFileSizeString(mContext, record.getSize()));
            }
        }
    }

    protected View ensureViewFromStub(ListViewHolder vh, View v,
                                      int stubIdInViewHolder, int viewIdInViewHolder, int targetViewId) {
        View ret;
        ViewStub stub = vh.getView(stubIdInViewHolder, ViewStub.class);
        if (stub != null) {
            ret = stub.inflate();
        } else {
            ret = v.findViewById(targetViewId);
        }

        if (ret != null) {
            vh.addView(viewIdInViewHolder, ret);
        }
        return ret;
    }

    protected void _bindCreateFolderView(ListViewHolder vh, View v) {
        ThumbnailImageView thumbnail = vh.getView(FileListViewHolder.THUMBNAIL, ThumbnailImageView.class);
        ImageView fileTypeIcon = vh.getView(FileListViewHolder.FILE_TYPE_ICON, ImageView.class);
        ImageView createFolderIcon = vh.getView(FileListViewHolder.CREATE_FOLDER_ICON, ImageView.class);
        if (thumbnail != null) {
            thumbnail.setImageDrawable(null);
        }

        if (fileTypeIcon != null) {
            fileTypeIcon.setVisibility(View.GONE);
        }

        if (createFolderIcon != null) {
            createFolderIcon.setVisibility(View.VISIBLE);
        }

        v.setContentDescription(mContext.getResources().getString(R.string.create_folder) + " " + mContext.getResources().getString(R.string.button));

        TextView name = vh.getView(FileListViewHolder.NAME, TextView.class);
        if (name != null) {
            name.setVisibility(View.VISIBLE);
            name.setText(mContext.getResources().getString(R.string.create_folder));
            name.setEllipsize(TextUtils.TruncateAt.END);
        }

        TextView size = vh.getView(FileListViewHolder.SIZE, TextView.class);
        if (size != null) {
            size.setVisibility(View.GONE);
        }

        TextView date = vh.getView(FileListViewHolder.DATE, TextView.class);
        if (date != null) {
            date.setVisibility(View.GONE);
        }

        if (mDecorator != null) {
            mDecorator.bindCreateFolderView(vh, v);
        }
    }

    private void _bindFolderDescriptionView(ListViewHolder vh, FileRecord record) {
        TextView folderDescriptionView = vh.getView(FileListViewHolder.FOLDER_DESCRIPTION, TextView.class);

        if (folderDescriptionView != null) {
            if (record.getFileType() == FileType.FOLDER) {
                String path = record.getPath() + "/" + record.getName();
                String folderDescription = RegionUtils.getFolderDescription(mContext, path);
                if (folderDescription != null) {
                    folderDescriptionView.setVisibility(View.VISIBLE);
                    folderDescriptionView.setText(folderDescription);
                } else {
                    folderDescriptionView.setVisibility(View.GONE);
                }
            } else {
                folderDescriptionView.setVisibility(View.GONE);
            }
        }
    }

    /**
     * Bind TTS info to view holder
     *
     * @param context
     * @param vh
     * @param v
     * @param record
     */
    protected void _bindContentDescription(Context context, ListViewHolder vh, View v, FileRecord record, int position) {
        if (v == null)
            return;

        boolean isCheckableDescription = mCheckMode && UiUtils.isCheckable(mContext, record, mNavigationInfo, mShareMode);
        boolean isCheck = false;
        boolean isCheckBox = false;
        String path = record.getPath() + "/" + record.getName();
        String folderDescription = RegionUtils.getFolderDescription(mContext, path);
        if (mNavigationInfo != null) {
            isCheckBox = !(mNavigationInfo.isSinglePickerMode());
        }

        if (isCheckableDescription) {
            if ((record.getStorageType() != StorageType.Cloud) && FileType.isDrmFileType(MediaFile.getFileType(record.getFullPath(), false)) && mListView != null) {
                isCheck = mListView.isSelectAll() || mListView.isItemChecked(position);
            }
        }

        if (isDetailList(v)) {
            if (record.getFileType() == FileType.FOLDER) {
                boolean showHidden = PreferenceUtils.getShowHiddenFiles(context);
                if (AppFeatures.SUPPORT_FOLDER_DESCRIPTION) {
                    if (isGridList() || folderDescription == null)
                        return;
                    folderDescription = folderDescription + " ";
                } else {
                    folderDescription = "";
                }
                if (isCheckableDescription) {
                    v.setContentDescription(UiUtils.getCheckableContentDescription(context, record.getName(), record.getFileType(), isCheck, isCheckBox)
                            + " " + folderDescription
                            + UiUtils.makeItemsString(mContext, record.getItemCount(showHidden)) + " " + UiUtils.makeTimeString(mContext, record.getDate()));
                } else {
                    v.setContentDescription(UiUtils.getContentDescription(context, record.getName(), record.getFileType(), false, isShareMode())
                            + " " + folderDescription
                            + UiUtils.makeItemsString(mContext, record.getItemCount(showHidden)) + " " + UiUtils.makeTimeString(mContext, record.getDate()));
                }

            } else {
                if (isCheckableDescription) {
                    v.setContentDescription(UiUtils.getCheckableContentDescription(context, record.getName(), record.getFileType(), isCheck, isCheckBox)
                            + " " + sizeSetter(record.getSize()) + " " + UiUtils.makeTimeString(mContext, record.getDate()));
                } else {
                    v.setContentDescription(UiUtils.getContentDescription(context, record.getName(), record.getFileType(), false, isShareMode()) + " "
                            + sizeSetter(record.getSize()) + " " + UiUtils.makeTimeString(mContext, record.getDate()));
                }
            }
        } else {
            if (AppFeatures.SUPPORT_FOLDER_DESCRIPTION) {
                if (isGridList() || folderDescription == null)
                    return;
                folderDescription = " " + folderDescription;
            } else {
                if (isCheckableDescription && mListView != null)
                    isCheck = mListView.isItemChecked(position);
                folderDescription = "";
            }
            if (isCheckableDescription) {
                v.setContentDescription(UiUtils.getCheckableContentDescription(context, record.getName(), record.getFileType(), isCheck, isCheckBox)
                        + folderDescription);
            } else {
                v.setContentDescription(UiUtils.getContentDescription(context, record.getName(), record.getFileType(), false, isShareMode())
                        + folderDescription);
            }
        }
    }

    private boolean isRecentList(View v) {
        boolean bRet = false;

        int id = v.getId();
        if (id == R.id.recent_grid_item) {
            bRet = true;
        }
        return bRet;
    }

    public boolean isGridList() {
        boolean bRet = false;
        if (mListView != null && mListView.getListView() instanceof GridView) {
            bRet = true;
        }
        return bRet;
    }

    private boolean isFastScrolling() {
        boolean bRet = false;
        if (mListView != null) {
            bRet = mListView.isFastScrolling();
        }
        return bRet;
    }

    private boolean isSplitBarPressed() {
        boolean bRet = false;
        if (mListView != null) {
            bRet = mListView.isSplitBarPressed();
        }
        return bRet;
    }

    protected boolean isDetailList(View v) {
        boolean bRet = false;

        int id = v.getId();
        if (id == R.id.file_detail_list_item) {
            bRet = true;
        }
        return bRet;
    }

    /**
     * Bind thumbnail to view holder
     *
     * @param context
     * @param vh
     * @param v
     * @param record
     */
    protected boolean _bindThumbnailView(Context context, ListViewHolder vh, View v, FileRecord record) {
        boolean bRet = false;

        ThumbnailImageView thumbnail = vh.getView(FileListViewHolder.THUMBNAIL, ThumbnailImageView.class);
        ImageView fileTypeIcon = vh.getView(FileListViewHolder.FILE_TYPE_ICON, ImageView.class);
        ImageView createFolderIcon = vh.getView(FileListViewHolder.CREATE_FOLDER_ICON, ImageView.class);
        ImageView view = null;
        if (thumbnail != null && fileTypeIcon != null) {
            thumbnail.setThumbnailView(mNavigationInfo.getCurFragment(), record, v);
            if (!isFastScrolling() && !isSplitBarPressed()) {
                view = ThumbnailMgr.getInstance(context).loadThumbnail(record, thumbnail, fileTypeIcon);
            } else {
                thumbnail.setImageBitmap(null);
            }

            if (view == null) {
                fileTypeIcon.setImageDrawable(MediaFile.getFileTypeDrawable(context, record));
                fileTypeIcon.setVisibility(View.VISIBLE);
            }

            bRet = (view == thumbnail);
        }

        if (createFolderIcon != null) {
            createFolderIcon.setVisibility(View.GONE);
        }
        return bRet;
    }

    /**
     * Bind check box to view holder
     *
     * @param vh
     * @param v
     * @param position
     */
    private void _bindCheckView(ListViewHolder vh, View v, FileRecord record, int position) {
        if (vh.getView(FileListViewHolder.CHECK_BOX) != null) {
            if (mCheckMode && isCheckable(position)) {
                showCheckBox(vh, v, position);
            } else {
                hideCheckBox(vh, v, record, position);
            }
        }
    }

    protected void showCheckBox(ListViewHolder vh, View v, int position) {
        View checkbox = vh.getView(FileListViewHolder.CHECK_BOX);

        v.setAlpha(1.0f);
        v.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_AUTO);
        if (checkbox != null) {
            if (checkbox instanceof ReverseCheckBox) {
                ((ReverseCheckBox) checkbox).setReverse(mSelectAll);
            }

            if (position == 0) {
                checkbox.animate().setDuration(500).setInterpolator(PathInterpolatorCompat.create(0.17f, 0.17f, 0.3f, 1f)).setListener(null).start();
            }

            checkbox.setVisibility(View.VISIBLE);
        }
    }

    protected void hideCheckBox(ListViewHolder vh, View v, FileRecord record, int position) {
        View checkbox = vh.getView(FileListViewHolder.CHECK_BOX);

        v.setActivated(false);  //clear selection state
        v.setAlpha(mShareMode ? 0.4f : 1.0f);
        v.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_AUTO);
        if (checkbox != null) {
            checkbox.setVisibility(View.GONE);
            if (UiUtils.needCheckableCheck(mNavigationInfo, record, mShareMode) && !record.isDirectory()) {
                checkbox.setVisibility(View.VISIBLE);
                if (!isCheckable(position)) {
                    v.setAlpha(0.4f);
                    if (checkbox instanceof ReverseCheckBox) {
                        if (mIsCheckable != null && mIsCheckable.size() > 0)
                            ((ReverseCheckBox) checkbox).setReverse(mIsCheckable.get(position));
                    }
                }
            }
        }
    }

    private void _bindPickerPlayIcon(Context context, ListViewHolder vh, View v, final FileRecord record) {
        if (mNavigationInfo != null && mNavigationInfo.isPickerMode() && !isGridList()) {
            int endPadding = 0;
            if (record.isAudioFileType()) {
                showPickerPlayIcon(vh, v, true);
                if (vh.getView(FileListViewHolder.PICKER_PLAY_ICON) != null) {
                    vh.getView(FileListViewHolder.PICKER_PLAY_ICON).setOnClickListener(new OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            if (UiUtils.isValidClick(v.getId())) {
                                AbsMyFilesFragment curFragment = mNavigationInfo.getCurFragment();
                                if (curFragment != null) {
                                    FileExecute.openFile(curFragment.getProcessId(), record, curFragment.getActivity());
                                } else {
                                    Log.e(this, "current fragment is null");
                                }
                            }
                        }
                    });
                }
                if (!isRecentList(v)) {
                    endPadding = context.getResources().getDimensionPixelSize(R.dimen.list_item_text_pickerplay_padding);
                }
            } else {
                showPickerPlayIcon(vh, v, false);
            }

            View name = vh.getView(FileListViewHolder.NAME);
            if (name != null) {
                name.setPaddingRelative(name.getPaddingStart(), name.getPaddingTop(), endPadding, name.getPaddingBottom());
            }
            View size = vh.getView(FileListViewHolder.SIZE);
            if (size != null) {
                size.setPaddingRelative(size.getPaddingStart(), size.getPaddingTop(), endPadding, size.getPaddingBottom());
            }
            View description = vh.getView(FileListViewHolder.DESCRIPTION);
            if (description != null) {
                description.setPaddingRelative(description.getPaddingStart(), description.getPaddingTop(), endPadding, description.getPaddingBottom());
            }

        }
    }

    private void showPickerPlayIcon(ListViewHolder vh, View v, boolean bShow) {
        int show = (bShow ? View.VISIBLE : View.GONE);
        View pickerPlayIcon = vh.getView(FileListViewHolder.PICKER_PLAY_ICON);
        if (bShow) {
            if (pickerPlayIcon == null) {
                pickerPlayIcon = getPickerPlayIconView(vh, v);
            }
        }

        if (pickerPlayIcon != null) {
            pickerPlayIcon.setVisibility(show);
        }
    }

    private View  getPickerPlayIconView(ListViewHolder vh, View v) {
        View ret = null;
        ViewStub stub = vh.getView(FileListViewHolder.PICKER_PLAY_ICON_STUB, ViewStub.class);
        if (stub != null) {
            stub.inflate();
            ret = v.findViewById(R.id.pickerplay_icon);
            vh.addView(FileListViewHolder.PICKER_PLAY_ICON, ret);
        }
        return ret;
    }

    protected void _bindProgressSync(Context context, ListViewHolder vh, View v, FileRecord record, boolean isShow) {
        showProgressSyncBar(vh, v, isShow);
        int endPadding = context.getResources().getDimensionPixelSize(R.dimen.list_item_text_pickerplay_padding);

        TextView name = vh.getView(FileListViewHolder.NAME, TextView.class);
        if (name != null) {
            name.setAlpha(isShow ? 0.37f : 1f);
            if (!isGridList()) {
                name.setPaddingRelative(name.getPaddingStart(), name.getPaddingTop(), endPadding, name.getPaddingBottom());
            }
        }

        TextView size = vh.getView(FileListViewHolder.SIZE, TextView.class);
        if (size != null) {
            size.setVisibility((isShow && !isGridList()) ? View.GONE : View.VISIBLE);
        }

        ImageView folderIcon = vh.getView(FileListViewHolder.FILE_TYPE_ICON, ImageView.class);
        if (folderIcon != null) {
            folderIcon.setAlpha(isShow ? 0.37f : 1f);
        }

        TextView date = vh.getView(FileListViewHolder.DATE, TextView.class);
        if (date != null) {
            date.setAlpha(isShow ? 0.37f : 1f);
        }

        if (mDecorator != null) {
            mDecorator.bindProgressSync(vh, v, record, isShow);
        }
    }

    private void showProgressSyncBar(ListViewHolder vh, View v, boolean bShow) {
        int show = (bShow ? View.VISIBLE : View.GONE);
        View progressSync = vh.getView(FileListViewHolder.PROGRESS_SYNC);
        if (bShow) {
            if (progressSync == null) {
                progressSync = getProgressSyncBarView(vh, v);
            }
        }

        if (progressSync != null) {
            progressSync.setVisibility(show);
        }
    }

    private View getProgressSyncBarView(ListViewHolder vh, View v) {
        View ret = null;
        ViewStub stub = vh.getView(FileListViewHolder.PROGRESS_SYNC_STUB, ViewStub.class);
        if (stub != null) {
            stub.inflate();
            ret = v.findViewById(R.id.progress_sync);
            vh.addView(FileListViewHolder.PROGRESS_SYNC, ret);
        }
        return ret;
    }

    @Override
    public View newView(Context context, Cursor c, ViewGroup parent) {
        View v = super.newView(context, c, parent);
        v.setTag(createViewHolder(v));
        return v;
    }

    private ListViewHolder createViewHolder(View v) {
        ListViewHolder ret = _createViewHolder(v);

        if (mDecorator != null) {
            mDecorator.createViewHolder(v, ret);
        }

        return ret;
    }

    protected ListViewHolder _createViewHolder(View v) {
        ListViewHolder vh = ListViewHolder.createHolder(FileListViewHolder.MAX);

        vh.addView(FileListViewHolder.CONTENTS_CONTAINER, v.findViewById(R.id.contents_container));
        vh.addView(FileListViewHolder.CHECK_BOX, getCheckboxView(v));
        vh.addView(FileListViewHolder.NAME, v.findViewById(R.id.file_name));
        vh.addView(FileListViewHolder.FOLDER_DESCRIPTION, v.findViewById(R.id.folder_description));
        vh.addView(FileListViewHolder.SIZE, v.findViewById(R.id.file_size));
        vh.addView(FileListViewHolder.DATE, v.findViewById(R.id.file_date));
        vh.addView(FileListViewHolder.DESCRIPTION, v.findViewById(R.id.description));
        vh.addView(FileListViewHolder.THUMBNAIL, v.findViewById(R.id.thumbnail));
        vh.addView(FileListViewHolder.FILE_TYPE_ICON, v.findViewById(R.id.file_type_icon));
        vh.addView(FileListViewHolder.PICKER_PLAY_ICON_STUB, v.findViewById(R.id.pickerplay_icon_stub));
        vh.addView(FileListViewHolder.GROUP_HEADER_STUB, v.findViewById(R.id.group_header_container_stub));
        vh.addView(FileListViewHolder.GROUP_HEADER, v.findViewById(R.id.group_header_container));
        vh.addView(FileListViewHolder.PROGRESS_SYNC_STUB, v.findViewById(R.id.progress_sync_stub));
        vh.addView(FileListViewHolder.CREATE_FOLDER_ICON, v.findViewById(R.id.create_folder_icon));

        return vh;
    }

    private View getCheckboxView(View parentView) {
        View ret = null;
        ViewStub stub = (ViewStub) parentView.findViewById(R.id.check_stub);
        if (stub != null) {
            if (mNavigationInfo != null) {
                if (mNavigationInfo.getNavigationMode() == NavigationMode.Pick_one_file) {
                    stub.setLayoutResource(R.layout.list_item_radiobutton_stub_common);
                }
            }
            if (AppFeatures.isTabletUIMode() && isGridList()) {
                stub.setLayoutResource(R.layout.list_item_grid_checkbox_stub_tablet);
            }
            try {
                ret = stub.inflate();
            } catch (InflateException e) {
                Log.e(this, "InflateException:" + e.toString());
            }
        }

        return ret;
    }

    public String[] getProjection() {
        return mTableInfo.getProjection();
    }

    public void setCheckMode(boolean bShow, boolean isShare) {
        mCheckMode = bShow;

        if (mShareMode != isShare) {
            mShareMode = isShare;
            clearPreValue();
        }
        if (getStorageType() == StorageType.Trash) {
            clearPreValue();
        }
    }

    private boolean isShareMode() {
        return mShareMode;
    }

    public boolean isCheckMode() {
        return mCheckMode;
    }

    public boolean isCheckable(int nPos) {
        boolean bRet = true;
        Boolean cache = null;

        if (nPos < mIsCheckable.size()) {
            cache = mIsCheckable.get(nPos);
        }
        if (cache == null) {
            if (mGroupSizes != null && isGroupHeader(nPos)) {
                bRet = false;
            } else {
                FileRecord record = getFileRecord(nPos);
                if (record != null) {
                    if (UiUtils.needCheckableCheck(mNavigationInfo, record, mShareMode)) {
                        bRet = UiUtils.isCheckable(mContext, record, mNavigationInfo, mShareMode);
                    }
                }
            }
            mIsCheckable.put(nPos, bRet);
        } else {
            bRet = cache;
        }
        return bRet;
    }

    public Uri getUri() {
        return Uri.parse(mTableInfo.getUri());
    }

    public abstract String getSelection();

    public abstract String[] getSelectionArgs();

    public String getOrderBy() {
        return getDefaultOrder(mContext, mTableInfo, getCurNavigationInfo());
    }

    public static String getDefaultOrder(Context context, DbTableInfo dbTableInfo, NavigationInfo curNaviInfo) {

        int type = PreferenceUtils.getSortByType(context, curNaviInfo);
        int order = PreferenceUtils.getSortByOrder(context, curNaviInfo);

        String ret = "";
        String strAsc = (order == 0) ? "ASC" : "DESC";
        String isDirColumn = dbTableInfo.getColumnName(COLUMN_ID.IS_DIRECTORY);
        String orderColumn = null;

        if (isDirColumn != null) {
            if (dbTableInfo.getTableName().equals(CategoryDbTableInfo.getInstance().getTableName())) {
                ret = dbTableInfo.getColumnQuery(COLUMN_ID.IS_DIRECTORY) + ", ";
            } else {
                ret = isDirColumn + " DESC, ";
            }
        }

        switch (type) {
            case SortByType.TIME:
                orderColumn = dbTableInfo.getColumnName(COLUMN_ID.DATE);
                break;
            case SortByType.TYPE:
                orderColumn = dbTableInfo.getColumnName(COLUMN_ID.EXT);
                break;
            case SortByType.SIZE:
                orderColumn = dbTableInfo.getColumnName(COLUMN_ID.SIZE);
                break;
        }

        if (orderColumn != null) {
            ret += orderColumn + " " + strAsc + ", ";
        }

        ret += dbTableInfo.getColumnName(COLUMN_ID.NAME) + " COLLATE LOCALIZED " + strAsc;

        return ret;
    }

    public FileRecord getFileRecord(int position) {
        FileRecord ret = getFileRecordFromCache(position);
        if (ret == null) {
            Cursor c = getCursor();
            int cursorPosition = getItemPosition(position);
            if (c == null || c.isClosed() || c.getCount() <= cursorPosition || isGroupHeader(position)) {
                Log.d(this, String.format(Locale.getDefault(), "getFileRecord : cursor is not proper (%d)", position));
                return null;
            }

            try {
                c.moveToPosition(cursorPosition);
                ret = getFileRecord(c);
                addFileRecordFromCache(position, ret);
            } catch (IllegalStateException e) {
                Log.e(this, "IllegalStateException:" + e.toString());
            }
        }

        return ret;
    }

    private FileRecord getFileRecordFromCache(int position) {
        FileRecord ret = null;
        if (mRecords != null) {
            ret = mRecords.get(position);
        }
        return ret;
    }

    private void addFileRecordFromCache(int position, FileRecord record) {
        if (mRecords != null && record != null) {
            mRecords.put(position, record);
        }
    }

    public String getFilePath(int position) {
        Cursor c = getCursor();
        if (c == null || c.isClosed() || c.getCount() <= position) {
            Log.d(this, String.format(Locale.getDefault(), "getFilePath : cursor is not proper (%d)", position));
            return null;
        }
        c.moveToPosition(getItemPosition(position));
        return getFilePath(c);
    }

    public void selectAll(boolean selectAll) {
        mSelectAll = selectAll;
    }

    public void changeContentDescription(View v, boolean isShown) {
        if (v.getContentDescription() == null)
            return;
        String contentDescription;
        if (isShown)
            contentDescription = (v.getContentDescription().toString()).replace(
                    mContext.getResources().getString(R.string.tts_not_ticked_t_tts),
                    mContext.getResources().getString(R.string.tts_ticked_t_tts));
        else
            contentDescription = (v.getContentDescription().toString()).replace(mContext.getResources().getString(R.string.tts_ticked_t_tts),
                    mContext.getResources().getString(R.string.tts_not_ticked_t_tts));

        v.setContentDescription(contentDescription);
    }

    private String sizeSetter(long fileSize) {
        String formatSize = Formatter.formatFileSize(mContext, fileSize);

        if (fileSize < FileUtils.KILO_BYTES) {
            formatSize = fileSize + mContext.getResources().getString(R.string.bytes_tts);
        }

        return formatSize;
    }

    public void clearPreValue() {
        mIsCheckable.clear();
    }

    public void onLoadFinished(Cursor data) {
        initItemList();

        AbsMyFilesFragment fragment = mNavigationInfo.getCurFragment();
        if (!(fragment instanceof AbsLeftPanelFragment) && !(fragment instanceof TabletLeftPanelFragment)) {
            int curTotCnt = data.getCount();

            if (curTotCnt != 0) {
                setListViewPos(fragment);
            } else {
                setEmptyListView(fragment);
            }

            clearFocus();
        }

        doFragmentLoadFinished(fragment, data);
    }

    private void initItemList() {
        if (mRecords != null) {
            mRecords = null;
        }
        mRecords = new LruCache<>(128);
    }

    private void setListViewPos(AbsMyFilesFragment fragment) {
        int nPos = mNavigationInfo.getCurListPosition();
        FileRecord focusRecord = mNavigationInfo.getFocusRecord();

        if (focusRecord != null) {
            nPos = getRecordPos(focusRecord);
        }

        fragment.clearEmptyView();

        if (mListView != null) {
            if (AppFeatures.isTabletUIMode()) {
                if (nPos != -1) {
                    mListView.setPosition(nPos);
                }
            } else if (!mNavigationInfo.getIsSearchMode()) {
                if (nPos != -1) {
                    mListView.setPosition(nPos);
                } else {
                    if (mListView.getListView() != null) {
                        mListView.getListView().requestFocus();
                    }
                }
            }
        }
    }

    private void clearFocus() {
        mNavigationInfo.setCurListPosition(-1);
        mNavigationInfo.setFocusRecord(null);
    }

    private void setEmptyListView(AbsMyFilesFragment fragment) {
        fragment.setEmptyView();
        fragment.finishActionMode();
    }

    public int getEmptyTextId() {
        return R.string.no_files;
    }

    public int getEmptySubTextId() {
        return AppConstants.UNDEFINED;
    }

    public int getEmptyIconId() {
        return R.raw.myfile;
    }

    protected void doFragmentLoadFinished(AbsMyFilesFragment fragment, Cursor data) {
        fragment.onLoadFinished();
    }

    private int getRecordPos(FileRecord focus) {
        int nRet = 0;

        for (int i = 0; i < getCount(); ++i) {
            if (focus.equals(getFileRecord(i))) {
                nRet = i;
                break;
            }
        }

        return nRet;
    }

    public Object[] getCreateFolderItem() {
        return null;
    }

    public FileRecord getFileRecord(Cursor cursor) {
        FileRecord ret = _getFileRecord(cursor);
        if (ret != null) {
            if (mDecorator != null) {
                mDecorator.getFileRecord(cursor, ret);
            }
        }
        return ret;
    }

    protected abstract FileRecord _getFileRecord(Cursor cursor);

    public abstract String getFilePath(Cursor cursor);

    protected String getFilePath(Cursor cursor, int pathIndex, int nameIndex) {
        String ret = null;
        if (cursor != null) {
            String path = cursor.getString(pathIndex);
            String name = cursor.getString(nameIndex);
            ret = path + "/" + name;
        }
        return ret;
    }

    protected String getFilePath(Cursor cursor, int pathIndex) {
        String ret = null;

        if (cursor != null) {
            ret = cursor.getString(pathIndex);
        }
        return ret;
    }

    @Override
    public long getItemId(int position) {
        long ret = _getItemId(position);

        try {
            if (ret == 0) {
                ret = super.getItemId(position);
            }
        } catch (IllegalStateException e) {
            Log.e(this, "IllegalStateException:" + e.toString());
        } catch (StaleDataException e) {
            Log.e(this, "StaleDataException:" + e.toString());
        }
        return ret;
    }

    private long _getItemId(int position) {
        long ret = 0;
        FileRecord record = getFileRecord(position);
        if (record != null) {
            ret = record.hashCode();
        }
        return ret;
    }

    public abstract StorageType getStorageType();

    public int getDragPosition() {
        return mDragPosition;
    }

    public void setDragPosition(int position) {
        mDragPosition = position;
    }


    public void toggleExpand(int position) {
    }

    public AbsListViewImp getListView() {
        return mListView;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View ret = null;
        try {
            if (mDecorator != null) {
                ret = mDecorator.getView(position, convertView, parent);
            }
            if (ret == null) {
                if (mGroupSizes != null) {
                    int groupPosition = getGroupPosition(position);
                    if (isGroupHeader(position)) {
                        return getHeaderView(groupPosition, convertView, parent);
                    }
                    position = position - (groupPosition + 1); // convert list position to cursor position
                    if (position < 0) {
                        position = 0;
                    }
                }
                ret = super.getView(position, convertView, parent);
                if (ret != null) {
                    showGroupHeader((ListViewHolder) ret.getTag(), false);
                    if (mDecorator != null) {
                        mDecorator.scrapView(position, ret);
                    }
                }
            }
        } catch (IllegalStateException e) {
            Log.e(this, "IllegalStateException:" + e.toString());
        }
        return ret;
    }

    private View getHeaderView(int groupPosition, View convertView, ViewGroup parent) {
        if (convertView == null) {
            convertView = newView(mContext, null, parent);
        }
        ListViewHolder vh = (ListViewHolder) convertView.getTag();
        ViewGroup groupHeaderContainer = vh.getView(FileListViewHolder.GROUP_HEADER, ViewGroup.class);
        if (groupHeaderContainer == null) {
            groupHeaderContainer = (ViewGroup) ensureViewFromStub(vh, convertView,
                    FileListViewHolder.GROUP_HEADER_STUB, FileListViewHolder.GROUP_HEADER,
                    R.id.group_header_container);
        }
        showGroupHeader(vh, true);

        if (groupHeaderContainer != null) {
            if (groupHeaderContainer.getChildCount() == 0) {
                View groupHeaderView = _newGroupHeaderView(mContext, vh, groupPosition);
                if (groupHeaderView != null) {
                    groupHeaderContainer.addView(groupHeaderView, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
                }
            }
            _bindGroupHeaderView(mContext, vh, convertView, groupPosition);
        }
        return convertView;
    }

    private void showGroupHeader(ListViewHolder vh, boolean show) {
        if (mGroupSizes != null && vh != null) {
            View contentsContainer = vh.getView(FileListViewHolder.CONTENTS_CONTAINER);
            View groupHeader = vh.getView(FileListViewHolder.GROUP_HEADER);
            if (contentsContainer != null && groupHeader != null) {
                if (show) {
                    contentsContainer.setVisibility(View.GONE);
                    groupHeader.setVisibility(View.VISIBLE);
                } else {
                    contentsContainer.setVisibility(View.VISIBLE);
                    groupHeader.setVisibility(View.GONE);
                }
            }
        }
    }

    public int[] getGroupInfo() {
        return Arrays.copyOf(mGroupSizes, mGroupSizes.length);
    }

    protected void setGroupInfo(int[] groupSizes) {
        mGroupSizes = groupSizes;
    }

    protected int getGroupItemCount(int groupPosition) {
        int ret = 0;
        if (mGroupSizes != null) {
            ret = mGroupSizes[groupPosition];
        }
        return ret;
    }

    protected boolean isLastItemOfGroup(int position) {
        boolean ret = false;
        if (mGroupSizes != null) {
            int totalItemCount = 0;
            for (int groupSize : mGroupSizes) {
                totalItemCount = totalItemCount + (1/* group header */ + groupSize);
                if (position == totalItemCount - 1) {
                    ret = true;
                    break;
                }
            }
        }
        return ret;
    }

    public int getEmptyTextColor() {
        return mContext.getResources().getColor(R.color.no_item_text, null);
    }
}
